#pragma once

#include <map>
#include <string>
#include <iostream>

//运行时不可修改的变量
const int runtime_const = 1;
//编译期常量
constexpr int COMPLIE_CONST_ = 1;
//编译期常量
#define COMPILE_CONST 1


//给类型起别名的两种方式
typedef int int_a;
using int_b = int;

template<typename T>
//为map起别名
using int_map = std::map<int,T>;

//使用别名，省略了一个模板参数
extern int_map<std::string> m;


//自定义类，两个模板参数
template<typename T,typename U>
class Demo final{

};

//保留一个模板参数
template<typename T>
//起别名
using Demo_LONG = Demo<T,long>;
//使用别名
extern Demo_LONG<std::string> dl;

//可变模板参数类
template<typename ...T>
class Demo_CHANGLEABLE_PARAMS{};


//模板函数声明和实现都放在一个.h文件中
//可变模板参数函数
template<typename ...T>
void changeableParamsFunc(T... args)
{
    std::cout << sizeof...(T) << std::endl;
}

//定义一个指针类型
typedef void (*func)();
//定义一个函数类型
typedef void func1(int a,int b);
//循环遍历
void for_();

/**
 * 测试非类型模板参数
 * 
 * 这种写法表示
 * typename T:这是一个类型模板参数，它表示一个类型，可以在模板实例化时被替换为任何传入的类型
 * T a:这是一个非类型模板参数，这里 @a 是一个变量，其类型被限制为 T: 。这意味着 @a 必须在模板实例化时有一个具体的值，并且 @a 必须是 T: 类型的。
 * T必须是一个可以用作非类型模板参数的类型
 * c++中可以使用的非类型模板参数 类型
 *      整型
 *      枚举类型
 *      指向对象的指针(包括函数指针)
 *      指向成员对象的指针
 *      指向成员函数的指针
 */
template <typename T, T a>
T test_non_type_template_param()
{
    return a;
}